﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace TaskSwitcher
{
    public class TaskSwitcher
    {
        private static Win32.EnumWindowsCallbackPtr callBackPtr;
        private static List<Task> tasks;

        public static Task[] GetTasks()
        {
            callBackPtr = new Win32.EnumWindowsCallbackPtr(EnumWindowsCallback);
            tasks = new List<Task>();
            Win32.EnumWindows(callBackPtr, 0);
            return tasks.ToArray();
        }

        private static bool EnumWindowsCallback(int i, int lParam)
        {
            IntPtr hWnd = new IntPtr(i);
            if (IsTask(hWnd))
            {
                //Process ID
                uint pid = 0;
                Win32.GetWindowThreadProcessId(hWnd, out pid);

                //Process Name
                string pName = Process.GetProcessById((int)pid).ProcessName;

                //Window Text
                string title = GetWindowText(hWnd);
                if (string.IsNullOrEmpty(title))
                    return true;

                //Add task to temp list
                tasks.Add(new Task
                {
                    Handle = hWnd,
                    ProcessID = (int)pid,
                    ProcessName = pName,
                    Title = title
                });
            }
            return true;
        }

        public static bool IsTask(IntPtr hWnd)
        {
            //Check if it is a window
            bool isWindow = Win32.IsWindow(hWnd);

            //Check if it is visibleisible
            bool isVisible = Win32.IsWindowVisible(hWnd);

            //Check if it has a parent
            bool isParentless = Win32.GetParent(hWnd) == IntPtr.Zero;

            //Check if it is un-owned
            bool isUnowned = Win32.GetWindow(hWnd, Win32.GetWindowCmd.GW_OWNER) == IntPtr.Zero;

            //Check if it is a tooltip window
            bool isTooltip = (Win32.GetWindowLong(hWnd, Win32.GWL_EXSTYLE) & Win32.WS_EX_TOOLWINDOW) == Win32.WS_EX_TOOLWINDOW;

            //Check if it cannot be activated
            bool isNoActivate = (Win32.GetWindowLong(hWnd, Win32.GWL_EXSTYLE) & Win32.WS_EX_NOACTIVATE) == Win32.WS_EX_NOACTIVATE;

            //Determine if it is a proper task
            return (isWindow && isVisible && isParentless && isUnowned && !isTooltip && !isNoActivate);
        }

        public static void SwitchTo(IntPtr hwnd)
        {
            //Make sure we have a proper window
            if (Win32.IsWindow(hwnd))
            {
                //Get the current foreground window
                IntPtr hCurrWnd = Win32.GetForegroundWindow();
                if (hCurrWnd != IntPtr.Zero)
                {
                    //Get the current thread id
                    uint thisTID = Win32.GetCurrentThreadId();

                    //Get the thread id for the foreground window
                    uint currTID = Win32.GetWindowThreadProcessId(hCurrWnd, IntPtr.Zero);

                    //Maybe attach the current thread
                    if (thisTID != currTID)
                        Win32.AttachThreadInput(thisTID, currTID, true);

                    //Focus window
                    Win32.SetForegroundWindow(hwnd);
                    Win32.SetFocus(hwnd);

                    //Maybe dettach the current thread
                    if (thisTID != currTID)
                        Win32.AttachThreadInput(thisTID, currTID, false);

                    //Restore the window state, or simply show it
                    if (Win32.IsIconic(hwnd))
                        Win32.ShowWindow(hwnd, Win32.WindowShowStyle.SW_RESTORE);
                    else
                        Win32.ShowWindow(hwnd, Win32.WindowShowStyle.SW_SHOW);
                }
            }
        }

        public static string GetWindowText(IntPtr hWnd)
        {
            // Allocate correct string length first
            int length = Win32.GetWindowTextLength(hWnd);
            StringBuilder sb = new StringBuilder(length + 1);
            Win32.GetWindowText(hWnd, sb, sb.Capacity);
            return sb.ToString();
        }
    }
}
